import mongoose from 'mongoose';
import RoleDAO from '../dao/RoleDAO';
import UserRoleDAO from '../dao/UserRoleDAO';
import RolePermissionDAO from '../dao/RolePermissionDAO';
import { IRole, IRoleDocument } from '../models/role';
import { IUserRoleDocument } from '../models/userRole';
import { IRolePermissionDocument } from '../models/rolePermission';

/**
 * 角色服务类
 * 提供角色管理相关的业务逻辑
 */
export class RoleService {
  private roleDAO: RoleDAO;
  private userRoleDAO: UserRoleDAO;
  private rolePermissionDAO: RolePermissionDAO;

  constructor() {
    this.roleDAO = new RoleDAO();
    this.userRoleDAO = new UserRoleDAO();
    this.rolePermissionDAO = new RolePermissionDAO();
  }

  /**
   * 创建新角色
   * @param roleData 角色数据
   * @returns 创建的角色文档
   */
  async createRole(roleData: Partial<IRole>): Promise<IRoleDocument> {
    try {
      // 验证必填字段
      if (!roleData.name || !roleData.code) {
        throw new Error('Role name and code are required');
      }

      // 检查角色编码是否已存在
      const existingRole = await this.roleDAO.findByCode(roleData.code);
      if (existingRole) {
        throw new Error('Role code already exists');
      }

      // 设置默认值
      const roleToCreate: Partial<IRole> = {
        ...roleData,
        status: roleData.status ?? 1,
        level: roleData.level ?? 1
      };

      return await this.roleDAO.create(roleToCreate);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 更新角色
   * @param roleId 角色ID
   * @param updateData 更新数据
   * @returns 更新后的角色文档
   */
  async updateRole(
    roleId: mongoose.Types.ObjectId | string,
    updateData: Partial<IRole>
  ): Promise<IRoleDocument> {
    try {
      // 如果更新编码，检查是否已存在
      if (updateData.code) {
        const roleObjectId = typeof roleId === 'string' ? new mongoose.Types.ObjectId(roleId) : roleId;
        const existingRole = await this.roleDAO.findByCode(updateData.code);
        if (existingRole && !(existingRole as any)._id.equals(roleObjectId)) {
          throw new Error('Role code already exists');
        }
      }

      const updatedRole = await this.roleDAO.update(roleId, updateData);
      if (!updatedRole) {
        throw new Error('Role not found');
      }

      return updatedRole;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 删除角色
   * @param roleId 角色ID
   * @returns 是否删除成功
   */
  async deleteRole(roleId: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      // 检查角色是否可以删除（没有关联的用户和权限）
      const userRoles = await this.userRoleDAO.findByRoleId(roleId);
      if (userRoles.length > 0) {
        throw new Error('Cannot delete role with assigned users');
      }

      const rolePermissions = await this.rolePermissionDAO.findByRoleId(roleId);
      if (rolePermissions.length > 0) {
        throw new Error('Cannot delete role with assigned permissions');
      }

      const result = await this.roleDAO.delete(roleId);
      if (!result) {
        throw new Error('Failed to delete role');
      }

      return result;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 为用户分配角色
   * @param userId 用户ID
   * @param roleId 角色ID
   * @param assignedBy 分配者ID
   * @param systemId 系统ID（可选）
   * @param expiresAt 过期时间（可选）
   * @returns 用户角色关联文档
   */
  async assignRoleToUser(
    userId: mongoose.Types.ObjectId | string,
    roleId: mongoose.Types.ObjectId | string,
    assignedBy: mongoose.Types.ObjectId | string,
    systemId?: mongoose.Types.ObjectId | string,
    expiresAt?: Date
  ): Promise<IUserRoleDocument> {
    try {
      // 检查用户是否已有该角色
      const hasRole = await this.userRoleDAO.hasRole(userId, roleId, systemId);
      if (hasRole) {
        throw new Error('User already has this role');
      }

      // 创建用户角色关联
      const userRoleData = {
        userId: typeof userId === 'string' ? new mongoose.Types.ObjectId(userId) : userId,
        roleId: typeof roleId === 'string' ? new mongoose.Types.ObjectId(roleId) : roleId,
        assignedBy: typeof assignedBy === 'string' ? new mongoose.Types.ObjectId(assignedBy) : assignedBy,
        systemId: systemId ? (typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId) : undefined,
        status: 1,
        expiresAt
      };

      return await this.userRoleDAO.create(userRoleData);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 从用户移除角色
   * @param userId 用户ID
   * @param roleId 角色ID
   * @param systemId 系统ID（可选）
   * @returns 是否移除成功
   */
  async removeRoleFromUser(
    userId: mongoose.Types.ObjectId | string,
    roleId: mongoose.Types.ObjectId | string,
    systemId?: mongoose.Types.ObjectId | string
  ): Promise<boolean> {
    try {
      const removedCount = await this.userRoleDAO.batchRevoke(userId, [roleId], systemId);
      if (removedCount === 0) {
        throw new Error('Failed to remove role from user');
      }

      return true;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 为角色分配权限
   * @param roleId 角色ID
   * @param permissionIds 权限ID数组
   * @param assignedBy 分配者ID
   * @param systemId 系统ID（可选）
   * @param expiresAt 过期时间（可选）
   * @returns 角色权限关联文档数组
   */
  async assignPermissionsToRole(
    roleId: mongoose.Types.ObjectId | string,
    permissionIds: (mongoose.Types.ObjectId | string)[],
    assignedBy: mongoose.Types.ObjectId | string,
    systemId?: mongoose.Types.ObjectId | string,
    expiresAt?: Date
  ): Promise<IRolePermissionDocument[]> {
    try {
      return await this.rolePermissionDAO.batchAssign(
        roleId,
        permissionIds,
        assignedBy,
        systemId,
        expiresAt
      );
    } catch (error) {
      throw error;
    }
  }

  /**
   * 从角色移除权限
   * @param roleId 角色ID
   * @param permissionIds 权限ID数组
   * @param systemId 系统ID（可选）
   * @returns 是否移除成功
   */
  async removePermissionsFromRole(
    roleId: mongoose.Types.ObjectId | string,
    permissionIds: (mongoose.Types.ObjectId | string)[],
    systemId?: mongoose.Types.ObjectId | string
  ): Promise<boolean> {
    try {
      const removedCount = await this.rolePermissionDAO.batchRevoke(roleId, permissionIds, systemId);
      if (removedCount === 0) {
        throw new Error('Failed to remove permissions from role');
      }
      return true;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取角色详情
   * @param roleId 角色ID
   * @returns 角色文档
   */
  async getRoleById(roleId: mongoose.Types.ObjectId | string): Promise<IRoleDocument | null> {
    try {
      return await this.roleDAO.findById(roleId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据编码获取角色
   * @param code 角色编码
   * @returns 角色文档
   */
  async getRoleByCode(code: string): Promise<IRoleDocument | null> {
    try {
      return await this.roleDAO.findByCode(code);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取系统角色列表
   * @param systemId 系统ID
   * @returns 角色文档数组
   */
  async getSystemRoles(systemId: mongoose.Types.ObjectId | string): Promise<IRoleDocument[]> {
    try {
      const systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      return await this.roleDAO.findBySystemId(systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取用户在系统中的角色
   * @param userId 用户ID
   * @param systemId 系统ID
   * @returns 用户角色关联文档数组
   */
  async getUserRolesInSystem(
    userId: mongoose.Types.ObjectId | string,
    systemId: mongoose.Types.ObjectId | string
  ): Promise<IUserRoleDocument[]> {
    try {
      return await this.userRoleDAO.getUserRolesInSystem(userId, systemId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取角色的权限列表
   * @param roleId 角色ID
   * @param systemId 系统ID（可选）
   * @returns 角色权限关联文档数组
   */
  async getRolePermissions(
    roleId: mongoose.Types.ObjectId | string,
    systemId?: mongoose.Types.ObjectId | string
  ): Promise<IRolePermissionDocument[]> {
    try {
      return await this.rolePermissionDAO.findByRoleId(roleId, systemId);
    } catch (error) {
      throw error;
    }
  }
}

export default RoleService;